package com.banggood.common.config;

import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;
import java.sql.SQLException;

/**
 *
 * @author weihuajiang
 * @date 2017/9/16
 */
@Slf4j
@Configuration
public class DruidAutoConfiguration {

    /**
     * 连接地址
     */
    @Value("${spring.datasource.url}")
    private String dbUrl;

    /**
     * 用户名
     */
    @Value("${spring.datasource.username}")
    private String username;

    /**
     * 用户密码
     */
    @Value("${spring.datasource.password}")
    private String password;

    /**
     * 连接类
     */
    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;

    /**
     * 初始化大小
     */
    @Value("${spring.datasource.initial-size}")
    private int initialSize;

    /**
     * 最小连接池数量
     */
    @Value("${spring.datasource.min-idle}")
    private int minIdle;

    /**
     * 最大连接数
     */
    @Value("${spring.datasource.max-active}")
    private int maxActive;

    /**
     * 获取连接时等待时间, 单位毫秒
     */
    @Value("${spring.datasource.max-wait}")
    private int maxWait;

    /**
     * 1、Destroy线程会检测连接的间隔时间；2、testWhileIdle的判断依据，详细看testWhileIdle属性的说明。
     */
    @Value("${spring.datasource.time-between-eviction-runs-millis}")
    private int timeBetweenEvictionRunsMillis;

    /**
     * 把空闲时间超过minEvictableIdleTimeMillis毫秒的连接断开, 直到连接池中的连接数到minIdle为止
     */
    @Value("${spring.datasource.min-evictable-idle-time-millis}")
    private int minEvictableIdleTimeMillis;

    /**
     * 检测连接是否有效的sql
     */
    @Value("${spring.datasource.validation-query}")
    private String validationQuery;

    /**
     * 建议配置为true，不影响性能，并且保证安全性。申请连接的时候检测，并查看连接是否有效
     */
    @Value("${spring.datasource.test-while-idle}")
    private boolean testWhileIdle;

    /**
     * 申请连接时执行validationQuery检测连接是否有效
     */
    @Value("${spring.datasource.test-on-borrow}")
    private boolean testOnBorrow;

    /**
     * 归还连接时执行validationQuery检测连接是否有效
     */
    @Value("${spring.datasource.test-on-return}")
    private boolean testOnReturn;

    /**
     * 是否缓存preparedStatement，也就是PSCache。PSCache对支持游标的数据库性能提升巨大，比如说oracle。在mysql下建议关闭。
     */
    @Value("${spring.datasource.pool-prepared-statements}")
    private boolean poolPreparedStatements;

    /**
     * 要启用PSCache，必须配置大于0，当大于0时，poolPreparedStatements自动触发修改为true
     */
    @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
    private int maxPoolPreparedStatementPerConnectionSize;

    /**
     * 拦截器
     */
    @Value("${spring.datasource.filters}")
    private String filters;

    /**
     * 有一个作用是可以加密数据库密码，具体的待研究
     * todo 使用druid来加密线上密码
     */
    @Value("{spring.datasource.connection-properties}")
    private String connectionProperties;

    /**
     * 声明其为Bean实例  在同样的DataSource中，首先使用被标注的DataSource
     * @return DataSource datasource
     */
    @Bean
    @Primary
    public DataSource dataSource() {
        DruidDataSource datasource = new DruidDataSource();

        datasource.setUrl(this.dbUrl);
        datasource.setUsername(username);
        datasource.setPassword(password);
        datasource.setDriverClassName(driverClassName);

        //configuration
        datasource.setInitialSize(initialSize);
        datasource.setMinIdle(minIdle);
        datasource.setMaxActive(maxActive);
        datasource.setMaxWait(maxWait);
        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        datasource.setValidationQuery(validationQuery);
        datasource.setTestWhileIdle(testWhileIdle);
        datasource.setTestOnBorrow(testOnBorrow);
        datasource.setTestOnReturn(testOnReturn);
        datasource.setPoolPreparedStatements(poolPreparedStatements);
        datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        try {
            datasource.setFilters(filters);
        } catch (SQLException e) {
            log.error("druid configuration initialization filter", e);
        }
        datasource.setConnectionProperties(connectionProperties);

        return datasource;
    }
}
